﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using Stateless;
using Stateless.Graph;

namespace ConsoleOpcUa01
{
    class Program

    {
        /// <summary>
        /// 事件类型
        /// </summary>
        private Dictionary<NodeId, Type> m_knownEventTypes;
        /// <summary>
        /// 事件类型映射
        /// </summary>
        private Dictionary<NodeId, NodeId> m_eventTypeMappings;


        private static StateMachine<RobotSystemStates, RobotSystemEvents> _robotStateMachine;
        static void Main(string[] args)
        {
            // 状态机设置
            _robotStateMachine  = new StateMachine<RobotSystemStates, RobotSystemEvents>(RobotSystemStates.PowerOn);
            // 开机
            _robotStateMachine.Configure(RobotSystemStates.PowerOn)
                .Permit(RobotSystemEvents.ExtYMoving, RobotSystemStates.ExtYMoving);

            
            _robotStateMachine.OnUnhandledTrigger((state, trigger) => { Console.WriteLine("未处理"+ trigger.ToString()); });


            Console.WriteLine("【1】创建ApplicationConfiguration...");
            var config = UpcUaClient.CreateAppConfiguration();
            config.Validate(ApplicationType.Client).GetAwaiter().GetResult();
            if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
            {
                config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
            }

            var application = new Opc.Ua.Configuration.ApplicationInstance
            {
                ApplicationName = "MyHomework",
                ApplicationType = ApplicationType.Client,
                ApplicationConfiguration = config
            };
            application.CheckApplicationInstanceCertificate(false, 2048).GetAwaiter().GetResult();
           
            var host = Dns.GetHostName();

            Console.WriteLine("【2】创建Session...");
            Task<Session> session =  UpcUaClient.ConnectOpcServer("opc.tcp://localhost:49320/",config);
            Console.WriteLine("【3】创建subscription...");
            var subscription=CreateSubscription(session.Result,50);
            Console.WriteLine("【4】增加Event监听.");
             
            Console.WriteLine("【4】增加监控项目.");
            AddMonitorItem(subscription);
            Console.WriteLine("【5】开始订阅.");
            
            subscription.Create();
            ConsoleOpcUa01.UpcUaClient.Write(session.Result,"ns=2;s=MES.DEV01.CURRENT_PIECE",13,"aabbccdd");
             Console.ReadKey(true);
              Console.ReadKey(true);
        }

       
        
        /// <summary>
        /// 在会话中新增一个订阅
        /// </summary>
        /// <param name="session"></param>
        /// <returns></returns>
        private static Subscription CreateSubscription(Session session,int publishingInterval)
        {

            var subscription = new Subscription(session.DefaultSubscription)
            {
                PublishingInterval = publishingInterval,
                PublishingEnabled = true

            };
            
            subscription.DefaultItem.AttributeId = Attributes.Value;
            subscription.DefaultItem.MonitoringMode = MonitoringMode.Reporting;
            subscription.DefaultItem.SamplingInterval =50;
            subscription.DefaultItem.QueueSize = 0;
            subscription.DefaultItem.DiscardOldest = true;
            session.AddSubscription(subscription);
            
            return subscription;

        }

        private static void AddMonitorItem(Subscription subscription)
        {
            //定义MonitorItems默认值
            var item = new MonitoredItem(subscription.DefaultItem)
            {
                StartNodeId = "ns=2;s=POLISH.RobotPLC.MEM.HMI在线",
                DisplayName = "HMI在线信号"
               
            };
            item.Notification+= monitoredItem_Notification;
            subscription.AddItem(item);
            
            //subscription.AddItem(CreateMonitorItems("ns=2;s=POLISH.RobotPLC.MEM.HMI在线"));
           subscription.AddItem(CreateMonitorItems("ns=2;s=POLISH.RobotPLC.EXTY.ExtYGoto","下个位置"));
           subscription.AddItem(CreateMonitorItems("ns=2;s=POLISH.RobotPLC.EXTY.ExtYOnPosition","导轨就位"));
            subscription.AddItem(CreateMonitorItems("ns=2;s=POLISH.RobotPLC.EXTY.ExtYPosition","当前位置"));
            



        }
        /// <summary>
        /// 创建一个监控项目
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        private static MonitoredItem CreateMonitorItems(NodeId nodeId,string displayName)
        {
           var  monitoredItem = new MonitoredItem();
           monitoredItem.StartNodeId = nodeId;
           monitoredItem.DisplayName = displayName;
           monitoredItem.AttributeId = Attributes.Value;
            monitoredItem.MonitoringMode = MonitoringMode.Reporting;
            monitoredItem.SamplingInterval = 50;
            monitoredItem.QueueSize = 0;
            monitoredItem.DiscardOldest = true;
            // 定义监控项的事件处理
            monitoredItem.Notification += monitoredItem_Notification;
            return monitoredItem;
             
        }
        /// <summary>
        /// 监控到数据变化的处理
        /// </summary>
        /// <param name="monitoredItem"></param>
        /// <param name="e"></param>
       static void  monitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
        {

            MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
            if (notification == null)
            {
                return;
            }
            
            string outStr = monitoredItem.StartNodeId.ToString()+ "value: " + Utils.Format("{0}", notification.Value.WrappedValue.ToString()) +
                                       ";  StatusCode: " + Utils.Format("{0}", notification.Value.StatusCode.ToString()) +
                                       ";  Source timestamp: " + notification.Value.SourceTimestamp.ToString() +
                                       ";  Server timestamp: " + notification.Value.ServerTimestamp.ToString();
            Console.WriteLine(outStr);
        }

        private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
        {
            foreach (var value in item.DequeueValues())
            {
                Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
            }
        }
    }
}
